/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package persistencia.controller.jpa;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import persistencia.controller.jpa.exceptions.NonexistentEntityException;
import persistencia.entidade.Categoria;
import persistencia.entidade.Registro;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author Novo usuário
 */
public class CategoriaJpaController implements Serializable, ICategoriaController{

    public CategoriaJpaController() {
        
    }
   
    @Override
    public String toString() {

        StringBuffer sb = new StringBuffer();
        List<Categoria> list = findCategoriaEntities();
        sb.append(String.valueOf(list.size()));
        sb.append("\n");
        for (Iterator<Categoria> it = list.iterator(); it.hasNext();) {
            Categoria cat = it.next();
            sb.append(cat.getCategoriaId());
            sb.append("|");
            sb.append(cat.getNome());
            sb.append("|");
            if (cat.getCategoriaPai() != null) {
                sb.append(cat.getCategoriaPai().getCategoriaId());
            }
            sb.append("|");
            String s = cat.getResumoFilhos();
            if (s == null || "null".equals(s)) {
                s = "";
            }
            sb.append(s);
            sb.append("|");

            List<Registro> regList = cat.getRegistroCollection();

            sb.append(regList.size());
            sb.append("|");
            for (Iterator<Registro> regIt = regList.iterator(); regIt.hasNext();) {
                Registro reg = regIt.next();
                sb.append(reg.getRegistroId());
                sb.append("|");
            }
            sb.delete(sb.length() - 1, sb.length());
            sb.append("\n");
        }

        return sb.toString();
    }

    public void create(Categoria categoria) {
        if (categoria.getRegistroCollection() == null) {
            categoria.setRegistroCollection(new ArrayList<Registro>());
        }
        if (categoria.getCategoriaCollection() == null) {
            categoria.setCategoriaCollection(new ArrayList<Categoria>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Categoria categoriaPai = categoria.getCategoriaPai();
            if (categoriaPai != null) {
                categoriaPai = em.getReference(categoriaPai.getClass(), categoriaPai.getCategoriaId());
                categoria.setCategoriaPai(categoriaPai);
            }
            List<Registro> attachedRegistroCollection = new ArrayList<Registro>();
            for (Registro registroCollectionRegistroToAttach : categoria.getRegistroCollection()) {
                registroCollectionRegistroToAttach = em.getReference(registroCollectionRegistroToAttach.getClass(), registroCollectionRegistroToAttach.getRegistroId());
                attachedRegistroCollection.add(registroCollectionRegistroToAttach);
            }
            categoria.setRegistroCollection(attachedRegistroCollection);
            List<Categoria> attachedCategoriaCollection = new ArrayList<Categoria>();
            for (Categoria categoriaCollectionCategoriaToAttach : categoria.getCategoriaCollection()) {
                categoriaCollectionCategoriaToAttach = em.getReference(categoriaCollectionCategoriaToAttach.getClass(), categoriaCollectionCategoriaToAttach.getCategoriaId());
                attachedCategoriaCollection.add(categoriaCollectionCategoriaToAttach);
            }
            categoria.setCategoriaCollection(attachedCategoriaCollection);
            em.persist(categoria);
            if (categoriaPai != null) {
                categoriaPai.getCategoriaCollection().add(categoria);
                categoriaPai = em.merge(categoriaPai);
            }
            for (Registro registroCollectionRegistro : categoria.getRegistroCollection()) {
                registroCollectionRegistro.getCategoriaCollection().add(categoria);
                registroCollectionRegistro = em.merge(registroCollectionRegistro);
            }
            for (Categoria categoriaCollectionCategoria : categoria.getCategoriaCollection()) {
                Categoria oldCategoriaPaiOfCategoriaCollectionCategoria = categoriaCollectionCategoria.getCategoriaPai();
                categoriaCollectionCategoria.setCategoriaPai(categoria);
                categoriaCollectionCategoria = em.merge(categoriaCollectionCategoria);
                if (oldCategoriaPaiOfCategoriaCollectionCategoria != null) {
                    oldCategoriaPaiOfCategoriaCollectionCategoria.getCategoriaCollection().remove(categoriaCollectionCategoria);
                    oldCategoriaPaiOfCategoriaCollectionCategoria = em.merge(oldCategoriaPaiOfCategoriaCollectionCategoria);
                }
            }
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public EntityManager getEntityManager(){
        return JdbcController.getInstance().getEntityManager();
    }

    public void edit(Categoria categoria) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Categoria persistentCategoria = em.find(Categoria.class, categoria.getCategoriaId());
            Categoria categoriaPaiOld = persistentCategoria.getCategoriaPai();
            Categoria categoriaPaiNew = categoria.getCategoriaPai();
            List<Registro> registroCollectionOld = persistentCategoria.getRegistroCollection();
            List<Registro> registroCollectionNew = categoria.getRegistroCollection();
            List<Categoria> categoriaCollectionOld = persistentCategoria.getCategoriaCollection();
            List<Categoria> categoriaCollectionNew = categoria.getCategoriaCollection();
            if (categoriaPaiNew != null) {
                categoriaPaiNew = em.getReference(categoriaPaiNew.getClass(), categoriaPaiNew.getCategoriaId());
                categoria.setCategoriaPai(categoriaPaiNew);
            }
            List<Registro> attachedRegistroCollectionNew = new ArrayList<Registro>();
            for (Registro registroCollectionNewRegistroToAttach : registroCollectionNew) {
                registroCollectionNewRegistroToAttach = em.getReference(registroCollectionNewRegistroToAttach.getClass(), registroCollectionNewRegistroToAttach.getRegistroId());
                attachedRegistroCollectionNew.add(registroCollectionNewRegistroToAttach);
            }
            registroCollectionNew = attachedRegistroCollectionNew;
            categoria.setRegistroCollection(registroCollectionNew);
            List<Categoria> attachedCategoriaCollectionNew = new ArrayList<Categoria>();
            for (Categoria categoriaCollectionNewCategoriaToAttach : categoriaCollectionNew) {
                categoriaCollectionNewCategoriaToAttach = em.getReference(categoriaCollectionNewCategoriaToAttach.getClass(), categoriaCollectionNewCategoriaToAttach.getCategoriaId());
                attachedCategoriaCollectionNew.add(categoriaCollectionNewCategoriaToAttach);
            }
            categoriaCollectionNew = attachedCategoriaCollectionNew;
            categoria.setCategoriaCollection(categoriaCollectionNew);
            categoria = em.merge(categoria);
            if (categoriaPaiOld != null && !categoriaPaiOld.equals(categoriaPaiNew)) {
                categoriaPaiOld.getCategoriaCollection().remove(categoria);
                categoriaPaiOld = em.merge(categoriaPaiOld);
            }
            if (categoriaPaiNew != null && !categoriaPaiNew.equals(categoriaPaiOld)) {
                categoriaPaiNew.getCategoriaCollection().add(categoria);
                categoriaPaiNew = em.merge(categoriaPaiNew);
            }
            for (Registro registroCollectionOldRegistro : registroCollectionOld) {
                if (!registroCollectionNew.contains(registroCollectionOldRegistro)) {
                    registroCollectionOldRegistro.getCategoriaCollection().remove(categoria);
                    registroCollectionOldRegistro = em.merge(registroCollectionOldRegistro);
                }
            }
            for (Registro registroCollectionNewRegistro : registroCollectionNew) {
                if (!registroCollectionOld.contains(registroCollectionNewRegistro)) {
                    registroCollectionNewRegistro.getCategoriaCollection().add(categoria);
                    registroCollectionNewRegistro = em.merge(registroCollectionNewRegistro);
                }
            }
            for (Categoria categoriaCollectionOldCategoria : categoriaCollectionOld) {
                if (!categoriaCollectionNew.contains(categoriaCollectionOldCategoria)) {
                    categoriaCollectionOldCategoria.setCategoriaPai(null);
                    categoriaCollectionOldCategoria = em.merge(categoriaCollectionOldCategoria);
                }
            }
            for (Categoria categoriaCollectionNewCategoria : categoriaCollectionNew) {
                if (!categoriaCollectionOld.contains(categoriaCollectionNewCategoria)) {
                    Categoria oldCategoriaPaiOfCategoriaCollectionNewCategoria = categoriaCollectionNewCategoria.getCategoriaPai();
                    categoriaCollectionNewCategoria.setCategoriaPai(categoria);
                    categoriaCollectionNewCategoria = em.merge(categoriaCollectionNewCategoria);
                    if (oldCategoriaPaiOfCategoriaCollectionNewCategoria != null && !oldCategoriaPaiOfCategoriaCollectionNewCategoria.equals(categoria)) {
                        oldCategoriaPaiOfCategoriaCollectionNewCategoria.getCategoriaCollection().remove(categoriaCollectionNewCategoria);
                        oldCategoriaPaiOfCategoriaCollectionNewCategoria = em.merge(oldCategoriaPaiOfCategoriaCollectionNewCategoria);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = categoria.getCategoriaId();
                if (findCategoria(id) == null) {
                    throw new NonexistentEntityException("The categoria with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroyRecursive(Integer id) {
        EntityManager em = null;
        Categoria categoria;
        try {
            em = getEntityManager();
            categoria = em.getReference(Categoria.class, id);
            List<Categoria> cats = categoria.getCategoriaCollection();
            for (Iterator<Categoria> it = cats.iterator(); it.hasNext();) {
                Categoria categoria1 = it.next();
                destroyRecursive(categoria1.getCategoriaId());
            }
            categoria.setRegistroCollection(new ArrayList<Registro>());
            categoria.setCategoriaCollection(new ArrayList<Categoria>());
            edit(categoria);
            destroy(categoria.getCategoriaId());
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(CategoriaJpaController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(CategoriaJpaController.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Categoria categoria;
            try {
                categoria = em.getReference(Categoria.class, id);
                categoria.getCategoriaId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The categoria with id " + id + " no longer exists.", enfe);
            }
            Categoria categoriaPai = categoria.getCategoriaPai();
            if (categoriaPai != null) {
                categoriaPai.getCategoriaCollection().remove(categoria);
                categoriaPai = em.merge(categoriaPai);
            }
            List<Registro> registroCollection = categoria.getRegistroCollection();
            for (Registro registroCollectionRegistro : registroCollection) {
                registroCollectionRegistro.getCategoriaCollection().remove(categoria);
                registroCollectionRegistro = em.merge(registroCollectionRegistro);
            }
            List<Categoria> categoriaCollection = categoria.getCategoriaCollection();
            for (Categoria categoriaCollectionCategoria : categoriaCollection) {
                categoriaCollectionCategoria.setCategoriaPai(null);
                categoriaCollectionCategoria = em.merge(categoriaCollectionCategoria);
            }
            em.remove(categoria);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Categoria> findCategoriaEntities() {
        return findCategoriaEntities(true, -1, -1);
    }

    public List<Categoria> findCategoriaEntities(int maxResults, int firstResult) {
        return findCategoriaEntities(false, maxResults, firstResult);
    }

    public List<Categoria> findCategoriaEntitiesSemFilhas() {
        List<Categoria> list = findCategoriaEntities();
        List<Categoria> listreturn = new ArrayList<Categoria>();
        for (Iterator<Categoria> it = list.iterator(); it.hasNext();) {
            Categoria categoria = it.next();
            if (categoria.getCategoriaCollection().size() == 0) {
                listreturn.add(categoria);

            }
        }
        return listreturn;
    }

    private List<Categoria> findCategoriaEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Categoria as o order by o.nome");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Categoria findCategoria(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Categoria.class, id);
        } finally {
            em.close();
        }
    }

    public List<Categoria> findCategoriaRaizEntities() {

        List<Categoria> catAll = findCategoriaEntities();
        List<Categoria> catRet = new LinkedList<Categoria>();
        for (Iterator<Categoria> it = catAll.iterator(); it.hasNext();) {
            Categoria categoria = it.next();
            if (categoria.getCategoriaPai() == null) {
                catRet.add(categoria);
            }

        }
        return catRet;
    }

    public int getCategoriaCount() {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from Categoria as o").getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
}
